﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Windows;
using System.Windows.Data;
using System.Windows.Input;
using GpgApi;
using Microsoft.Win32;
using WgpgCore;

namespace WgpgGUI
{
    public partial class MainWindow : Window
    {
        private DialogTasks m_taskDialog = null;
        private DialogEditor m_editorDialog = null;
        private ListCollectionView m_collectionView = null;

        public MainWindow()
        {
            InitializeComponent();

            m_collectionView = new ListCollectionView(KeyManager.Keys);
            m_collectionView.Filter = new Predicate<Object>(Filter);
            m_collectionView.CustomSort = new KeyNodeSort(true);
            m_collectionView.GroupDescriptions.Add(new PropertyGroupDescription { PropertyName = "Type" });
            keylistview.DataContext = m_collectionView;

            TaskManager.Instance.PropertyChanged += new PropertyChangedEventHandler(Instance_PropertyChanged);
        }

        private Boolean Filter(Object item)
        {
            KeyNodeFilter filter = new KeyNodeFilter();
            filter.Expression = searchFilter.Text;
            return filter.Match(item as KeyNode);
        }

        private void Instance_PropertyChanged(Object sender, PropertyChangedEventArgs e)
        {
            if (TaskManager.Instance.IsRunning)
            {
                ready_panel.Visibility = Visibility.Collapsed;
                StatusBar_Progress.Visibility = Visibility.Visible;
            }
            else
            {
                ready_panel.Visibility = Visibility.Visible;
                StatusBar_Progress.Visibility = Visibility.Collapsed;
            }
        }

        private void Search(Object sender, RoutedEventArgs e)
        {
            m_collectionView.Refresh();
        }

        private void OpenKeyInformationDialog(KeyId id)
        {
            DialogKeyInformation dlg = new DialogKeyInformation(this, id);
            dlg.ShowDialog();
        }

        private void ListViewDoubleClick(Object sender, MouseButtonEventArgs e)
        {
            KeyNode key = SelectedKey();
            if (key == null)
                return;

            OpenKeyInformationDialog(key.Id);
            e.Handled = true;
        }

        // ----------------------------------------------------------------------------------------

        private Int32 CountSelectedKeys()
        {
            return keylistview == null || keylistview.SelectedItems == null ? 0 : keylistview.SelectedItems.Count;
        }

        private Boolean KeySelected()
        {
            return CountSelectedKeys() > 0;
        }

        private KeyNode SelectedKey()
        {
            return KeySelected() ? keylistview.SelectedItems[0] as KeyNode : null;
        }

        private List<KeyNode> SelectedKeys()
        {
            if (!KeySelected())
                return null;

            List<KeyNode> keys = new List<KeyNode>();
            foreach (Object key in keylistview.SelectedItems)
            {
                KeyNode item = key as KeyNode;
                if (item != null)
                    keys.Add(item);
            }

            if (keys.Count == 0)
                return null;

            return keys;
        }

        // ----------------------------------------------------------------------------------------

        public static RoutedCommand OpenKeyInformationCommand = new RoutedCommand();
        public static RoutedCommand OpenTaskListCommand = new RoutedCommand();
        public static RoutedCommand AboutWgpgCommand = new RoutedCommand();
        public static RoutedCommand DecryptFileCommand = new RoutedCommand();
        public static RoutedCommand EncryptFileCommand = new RoutedCommand();
        public static RoutedCommand SignFileCommand = new RoutedCommand();
        public static RoutedCommand VerifyFileCommand = new RoutedCommand();
        public static RoutedCommand ExportKeyToFileCommand = new RoutedCommand();
        public static RoutedCommand ExportKeyToClipboardCommand = new RoutedCommand();
        public static RoutedCommand ImportKeyFromFileCommand = new RoutedCommand();
        public static RoutedCommand ExportPrivateKeyToClipboardCommand = new RoutedCommand();
        public static RoutedCommand OpenEditorCommand = new RoutedCommand();

        #region Command: Open Key Information
        private void OpenKeyInformation_CanExecute(Object sender, CanExecuteRoutedEventArgs e)
        {
            e.Handled = true;
            e.CanExecute = CountSelectedKeys() == 1;
        }

        private void OpenKeyInformation_Executed(Object sender, ExecutedRoutedEventArgs e)
        {
            e.Handled = true;

            KeyNode key = SelectedKey();
            if (key != null)
                OpenKeyInformationDialog(key.Id);
        }
        #endregion Command: Open Key Information

        #region Command: Open TaskList
        private void OpenTaskList_CanExecute(Object sender, CanExecuteRoutedEventArgs e)
        {
            e.Handled = true;
            e.CanExecute = true;
        }

        private void OpenTaskList_Executed(Object sender, ExecutedRoutedEventArgs e)
        {
            e.Handled = true;

            if (m_taskDialog == null)
            {
                m_taskDialog = new DialogTasks(this);
                m_taskDialog.Closed += new EventHandler((d_sender, d_e) => { m_taskDialog = null; });
            }

            m_taskDialog.Show();
            m_taskDialog.Focus();
        }
        #endregion Command: Open TaskList

        #region Command: Generate A Key
        private void GenerateKey_CanExecute(Object sender, CanExecuteRoutedEventArgs e)
        {
            e.Handled = true;
            e.CanExecute = true;
        }

        private void GenerateKey_Executed(Object sender, ExecutedRoutedEventArgs e)
        {
            e.Handled = true;
            GenerateKey.Generate(this);
        }
        #endregion Command: Generate A Key

        #region Command: Delete Key
        private void DeleteKey_CanExecute(Object sender, CanExecuteRoutedEventArgs e)
        {
            e.Handled = true;
            e.CanExecute = KeySelected();
        }

        private void DeleteKey_Executed(Object sender, ExecutedRoutedEventArgs e)
        {
            e.Handled = true;

            List<KeyNode> keys = SelectedKeys();
            if (keys == null)
                return;

            if (keys.Count == 1)
            {
                KeyNode key = keys[0];
                KeyUserInfoNode userinfo = key.UserInfos[0];

                String message = L10N.T("delete_key");
                message += "\n" + L10N.T("str_id", key.Id);
                message += "\n" + L10N.T("str_name", userinfo.Name);
                message += "\n" + L10N.T("str_email", userinfo.Email);
                if (userinfo.Comment != null)
                    message += "\n" + L10N.T("str_comment", userinfo.Comment);

                if (CustomMessageBox.Show(this, message, L10N.T("delete_key_title"), MessageBoxButton.YesNo, MessageBoxImage.Question, MessageBoxResult.No, null, L10N.T("button_delete"), L10N.T("button_cancel"), null, MessageBoxResult.No) != MessageBoxResult.Yes)
                    return;
            }
            else
            {
                if (CustomMessageBox.Show(this, L10N.T("delete_multiple_keys", keys.Count.ToString()), L10N.T("delete_key_title"), MessageBoxButton.YesNo, MessageBoxImage.Question, MessageBoxResult.No, null, L10N.T("button_delete"), L10N.T("button_cancel"), null, MessageBoxResult.No) != MessageBoxResult.Yes)
                    return;
            }

            List<KeyId> keyids = new List<KeyId>();
            foreach (KeyNode key in keys)
                keyids.Add(key.Id);

            GpgDeleteKeys deletekeys = new GpgDeleteKeys(keyids, false);
            deletekeys.ExecuteAsync((result) =>
            {
                KeyManager.RefreshAll();
            });
        }
        #endregion Command: Delete Key

        #region Command: Refresh
        private void Refresh_CanExecute(Object sender, CanExecuteRoutedEventArgs e)
        {
            e.Handled = true;
            e.CanExecute = true;
        }

        private void Refresh_Executed(Object sender, ExecutedRoutedEventArgs e)
        {
            e.Handled = true;
            KeyManager.RefreshAll();
        }
        #endregion Command: Refresh

        #region Command: About Wgpg
        private void AboutWgpg_CanExecute(Object sender, CanExecuteRoutedEventArgs e)
        {
            e.Handled = true;
            e.CanExecute = true;
        }

        private void AboutWgpg_Executed(Object sender, ExecutedRoutedEventArgs e)
        {
            e.Handled = true;

            DialogAboutWgpg about = new DialogAboutWgpg(this);
            about.ShowDialog();
        }
        #endregion Command: About Wgpg

        #region Command: Decrypt File
        private void DecryptFile_CanExecute(Object sender, CanExecuteRoutedEventArgs e)
        {
            e.Handled = true;
            e.CanExecute = true;
        }

        private void DecryptFile_Executed(Object sender, ExecutedRoutedEventArgs e)
        {
            e.Handled = true;
            Decrypt.File(this, null);
        }
        #endregion Command: Decrypt File

        #region Command: Encrypt File
        private void EncryptFile_CanExecute(Object sender, CanExecuteRoutedEventArgs e)
        {
            e.Handled = true;
            e.CanExecute = true;
        }

        private void EncryptFile_Executed(Object sender, ExecutedRoutedEventArgs e)
        {
            e.Handled = true;
            Encrypt.File(this, null);
        }
        #endregion Command: Encrypt File

        #region Command: Sign File
        private void SignFile_CanExecute(Object sender, CanExecuteRoutedEventArgs e)
        {
            e.Handled = true;
            e.CanExecute = KeyManager.Keys.Count > 0;
        }

        private void SignFile_Executed(Object sender, ExecutedRoutedEventArgs e)
        {
            e.Handled = true;
        }
        #endregion Command: Sign File

        #region Command: Verify File
        private void VerifyFile_CanExecute(Object sender, CanExecuteRoutedEventArgs e)
        {
            e.Handled = true;
            e.CanExecute = true;
        }

        private void VerifyFile_Executed(Object sender, ExecutedRoutedEventArgs e)
        {
            e.Handled = true;
        }
        #endregion Command: Verify File

        #region Command: Export Key To File
        private void ExportKeyToFile_CanExecute(Object sender, CanExecuteRoutedEventArgs e)
        {
            e.Handled = true;
            e.CanExecute = CountSelectedKeys() == 1;
        }

        private void ExportKeyToFile_Executed(Object sender, ExecutedRoutedEventArgs e)
        {
            KeyNode key = SelectedKey();
            if (key == null)
                return;

            e.Handled = true;

            Mouse.OverrideCursor = Cursors.Wait;

            GpgExportKey export = new GpgExportKey(key.Id, false);

            export.ExecuteAsync((result) =>
            {
                Mouse.OverrideCursor = null;

                if (export.ExportedKey == null)
                    return;

                SaveFileDialog dialog = new SaveFileDialog();
                dialog.Title = L10N.T("export_key_to_file");
                dialog.OverwritePrompt = true;
                dialog.CheckPathExists = true;
                dialog.Filter = "Wgpg file (*.asc)|*.asc";
                if (dialog.ShowDialog(this) != true)
                    return;

                Mouse.OverrideCursor = Cursors.Wait;

                using (StreamWriter wtr = new StreamWriter(dialog.FileName))
                {
                    wtr.Write(export.ExportedKey);
                }

                Mouse.OverrideCursor = null;
            });
        }
        #endregion Command: Export Key To File

        #region Command: Export Key To Clipboard
        private void ExportKeyToClipboard_CanExecute(Object sender, CanExecuteRoutedEventArgs e)
        {
            e.Handled = true;
            e.CanExecute = CountSelectedKeys() == 1;
        }

        private void ExportKeyToClipboard_Executed(Object sender, ExecutedRoutedEventArgs e)
        {
            KeyNode key = SelectedKey();
            if (key == null)
                return;

            e.Handled = true;

            Mouse.OverrideCursor = Cursors.Wait;

            GpgExportKey export = new GpgExportKey(key.Id, false);

            export.ExecuteAsync((result) =>
            {
                if (export.ExportedKey != null)
                    Clipboard.SetText(export.ExportedKey, TextDataFormat.Text);

                Mouse.OverrideCursor = null;
            });
        }
        #endregion Command: Export Key To Clipboard

        #region Command: Import Key From File
        private void ImportKeyFromFile_CanExecute(Object sender, CanExecuteRoutedEventArgs e)
        {
            e.Handled = true;
            e.CanExecute = true;
        }

        private void ImportKeyFromFile_Executed(Object sender, ExecutedRoutedEventArgs e)
        {
            e.Handled = true;

            OpenFileDialog dialog = new OpenFileDialog();
            dialog.Title = "Import a key";
            dialog.CheckFileExists = true;
            dialog.CheckPathExists = true;
            dialog.Filter = "Wgpg file (*.asc)|*.asc";
            if (dialog.ShowDialog() == false)
                return;

            GpgImportKey import = new GpgImportKey(dialog.FileName);
            import.ExecuteAsync((result) =>
            {
                if (result.Status == GpgInterfaceStatus.Error)
                {
                    if (result.Message == GpgInterfaceMessage.DataError)
                    {
                        CustomMessageBox.Show(this, "The selected file is not a key.", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
                        return;
                    }
                }

                Import p = import.Import;
                if (p == Import.Unchanged)
                {
                    CustomMessageBox.Show(this, "This key was already up-to-date in your keyring. Nothing changed", "Imported key", MessageBoxButton.OK, MessageBoxImage.Information);
                    return;
                }
                else if (p == Import.None)
                {
                    CustomMessageBox.Show(this, "Nothing changed", "Imported key", MessageBoxButton.OK, MessageBoxImage.Information);
                    return;
                }

                if (p == Import.NewKey)
                    CustomMessageBox.Show(this, "This key has been added to your keyring\nFingerprint: " + import.FingerPrint, "Imported key", MessageBoxButton.OK, MessageBoxImage.Information);
                else
                    CustomMessageBox.Show(this, "The key " + import.FingerPrint + " has changed", "Imported key", MessageBoxButton.OK, MessageBoxImage.Information);

                KeyManager.RefreshAll();
            });
        }
        #endregion Command: Import Key From File

        #region Command: Export Private Key To Clipboard

        private void ExportPrivateKeyToClipboard_CanExecute(Object sender, CanExecuteRoutedEventArgs e)
        {
            e.Handled = true;
            KeyNode node = SelectedKey();
            e.CanExecute = node != null && (node.Type & KeyType.Secret) == KeyType.Secret;
        }

        private void ExportPrivateKeyToClipboard_Executed(Object sender, ExecutedRoutedEventArgs e)
        {
            KeyNode key = SelectedKey();
            if (key == null)
                return;

            e.Handled = true;

            Mouse.OverrideCursor = Cursors.Wait;

            GpgExportKey export = new GpgExportKey(key.Id, true);

            export.ExecuteAsync((result) =>
            {
                if (export.ExportedKey != null)
                    Clipboard.SetText(export.ExportedKey, TextDataFormat.Text);

                Mouse.OverrideCursor = null;
            });
        }

        #endregion Command: Export Private Key To Clipboard

        #region Command: OpenEditor

        private void OpenEditor_CanExecute(Object sender, CanExecuteRoutedEventArgs e)
        {
            e.Handled = true;
            e.CanExecute = true;
        }

        private void OpenEditor_Executed(Object sender, ExecutedRoutedEventArgs e)
        {
            if (m_editorDialog == null)
                m_editorDialog = new DialogEditor();
            m_editorDialog.Show();
        }

        #endregion Command: OpenEditor
    }
}
